home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / DROPEXT.PAK / DROPEXT.C < prev    next >
C/C++ Source or Header  |  1997-05-05  |  18KB  |  617 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1994-1995 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. //---------------------------------------------------------------------------
  13. //
  14. // File: dropext.c
  15. //
  16. //  This file contains a sample source code of context menu extension handler.
  17. //
  18. //---------------------------------------------------------------------------
  19.  
  20. #include "priv.h"
  21.  
  22. //
  23. // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
  24. //
  25. #pragma data_seg(".text")
  26. #define INITGUID
  27. #include <initguid.h>
  28. #include "dropext.h"
  29. #pragma data_seg()
  30.  
  31. //
  32. // Function prototypes
  33. //
  34. HRESULT CALLBACK DropExt_CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR*);
  35.  
  36. //
  37. // Global variables
  38. //
  39. UINT g_cRefThisDll = 0;        // Reference count of this DLL.
  40. UINT g_cfNetResource = 0;    // Clipboard format
  41.  
  42. //---------------------------------------------------------------------------
  43. // LibMain
  44. //---------------------------------------------------------------------------
  45. #pragma argsused
  46. BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
  47. {
  48.      switch(dwReason)
  49.      {
  50.      case DLL_PROCESS_ATTACH:
  51.         break;
  52.      case DLL_PROCESS_DETACH:
  53.         break;
  54.  
  55.      case DLL_THREAD_DETACH:
  56.           break;
  57.  
  58.      case DLL_THREAD_ATTACH:
  59.      default:
  60.         break;
  61.      } // end switch()
  62.  
  63.      return TRUE;
  64. }
  65.  
  66. //---------------------------------------------------------------------------
  67. // DllCanUnloadNow
  68. //---------------------------------------------------------------------------
  69.  
  70. STDAPI DllCanUnloadNow(void)
  71. {
  72.     return ResultFromScode((g_cRefThisDll==0) ? S_OK : S_FALSE);
  73. }
  74.  
  75. //---------------------------------------------------------------------------
  76. //
  77. // DllGetClassObject
  78. //
  79. //  This is the entry of this DLL, which all the In-Proc server DLLs should
  80. // export. See the description of "DllGetClassObject" of OLE 2.0 reference
  81. // manual for detail.
  82. //
  83. //---------------------------------------------------------------------------
  84.  
  85. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppvOut)
  86. {
  87.     //
  88.     //  This DLL has only one class (CLSID_SampleDropExt). If a DLL supports
  89.     // multiple classes, it should have either multiple if-statements or
  90.     // efficient table lookup code.
  91.     //
  92.     if (IsEqualIID(rclsid, &CLSID_SampleDropExt))
  93.     {
  94.     //
  95.     //  We are supposed return the class object for this class. Instead
  96.     // of fully implementing it in this DLL, we just call a helper
  97.     // function in the shell DLL which creates a default class factory
  98.     // object for us. When its CreateInstance member is called, it
  99.     // will call back our create instance function (DropExt_CreateInstance).
  100.     //
  101.     return SHCreateDefClassObject(
  102.             riid,            //
  103.             ppvOut,            //
  104.             DropExt_CreateInstance, // callback function
  105.             &g_cRefThisDll,        // reference count of this DLL
  106.             &IID_IShellExtInit        // init interface
  107.             );
  108.     }
  109.  
  110.     return ResultFromScode(E_FAIL);
  111. }
  112.  
  113.  
  114. //---------------------------------------------------------------------------
  115. //
  116. // CSampleDropExt class
  117. //
  118. // In C++:
  119. //  class CSampleDropExt : protected IContextMenu, protected IShellExtInit
  120. //  {
  121. //  protected:
  122. //      UINT         _cRef;
  123. //      LPDATAOBJECT _pdtobj;
  124. //    HKEY         _hkeyProgID;
  125. //  public:
  126. //      CSampleDropExt() _cRef(1), _pdtobj(NULL), _hkeyProgID(NULL) {};
  127. //      ...
  128. //  };
  129. //
  130. //---------------------------------------------------------------------------
  131. typedef struct _CSampleDropExt    // smx
  132. {
  133.     IContextMenu    _ctm;           // 1st base class
  134.     IShellExtInit   _sxi;        // 2nd base class
  135.     UINT            _cRef;          // reference count
  136.     LPDATAOBJECT    _pdtobj;        // data object
  137.     HKEY        _hkeyProgID;    // reg. database key to ProgID
  138.     char        _szTargetFolder[MAX_PATH];
  139. } CSampleDropExt, * PSAMPLEDROPEXT;
  140.  
  141. #define SMX_OFFSETOF(x)            ((UINT)(&((PSAMPLEDROPEXT)0)->x))
  142. #define PVOID2PSMX(pv,offset)   ((PSAMPLEDROPEXT)(((LPBYTE)pv)-offset))
  143. #define PCTM2PSMX(pctm)            PVOID2PSMX(pctm, SMX_OFFSETOF(_ctm))
  144. #define PSXI2PSMX(psxi)            PVOID2PSMX(psxi, SMX_OFFSETOF(_sxi))
  145.  
  146. //
  147. // Vtable prototype
  148. //
  149. extern IContextMenuVtbl     c_SampleDropExt_CTMVtbl;
  150. extern IShellExtInitVtbl    c_SampleDropExt_SXIVtbl;
  151.  
  152. //---------------------------------------------------------------------------
  153. //
  154. // DropExt_CreateInstance
  155. //
  156. //  This function is called back from within IClassFactory::CreateInstance()
  157. // of the default class factory object, which is created by SHCreateClassObject.
  158. //
  159. //---------------------------------------------------------------------------
  160.  
  161. HRESULT CALLBACK DropExt_CreateInstance(LPUNKNOWN punkOuter,
  162.                         REFIID riid, LPVOID FAR* ppvOut)
  163. {
  164.     HRESULT hres;
  165.     PSAMPLEDROPEXT psmx;
  166.  
  167.     //
  168.     // Shell extentions typically does not support aggregation.
  169.     //
  170.     if (punkOuter) {
  171.     return ResultFromScode(CLASS_E_NOAGGREGATION);
  172.     }
  173.  
  174.     //
  175.     // in C++:
  176.     //  psmx = new CSampleDropExt();
  177.     //
  178.     psmx = LocalAlloc(LPTR, sizeof(CSampleDropExt));
  179.     if (!psmx) {
  180.     return ResultFromScode(E_OUTOFMEMORY);
  181.     }
  182.     psmx->_ctm.lpVtbl = &c_SampleDropExt_CTMVtbl;
  183.     psmx->_sxi.lpVtbl = &c_SampleDropExt_SXIVtbl;
  184.     psmx->_cRef = 1;
  185.     psmx->_pdtobj = NULL;
  186.     psmx->_hkeyProgID = NULL;
  187.     g_cRefThisDll++;
  188.  
  189.     //
  190.     // in C++:
  191.     //  hres = psmx->QueryInterface(riid, ppvOut);
  192.     //  psmx->Release();
  193.     //
  194.     // Note that the Release member will free the object, if QueryInterface
  195.     // failed.
  196.     //
  197.     hres = c_SampleDropExt_CTMVtbl.QueryInterface(&psmx->_ctm, riid, ppvOut);
  198.     c_SampleDropExt_CTMVtbl.Release(&psmx->_ctm);
  199.  
  200.     return hres;    // S_OK or E_NOINTERFACE
  201. }
  202.  
  203.  
  204. //---------------------------------------------------------------------------
  205. // CSampleDropExt::Initialize (IShellExtInit override)
  206. //---------------------------------------------------------------------------
  207. STDMETHODIMP DropExt_Initialize(LPSHELLEXTINIT psxi,
  208.         LPCITEMIDLIST pidlFolder,
  209.         LPDATAOBJECT pdtobj,
  210.         HKEY hkeyProgID)
  211. {
  212.      PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  213.  
  214.      // Initialize can be called more than once.
  215.      if (this->_pdtobj) {
  216.     this->_pdtobj->lpVtbl->Release(this->_pdtobj);
  217.      }
  218.  
  219.      if (this->_hkeyProgID) {
  220.     RegCloseKey(this->_hkeyProgID);
  221.      }
  222.  
  223.      // Duplicate the pdtobj pointer
  224.      if (pdtobj) {
  225.     this->_pdtobj = pdtobj;
  226.     pdtobj->lpVtbl->AddRef(pdtobj);
  227.      }
  228.  
  229.      // Duplicate the handle
  230.      if (hkeyProgID) {
  231.     RegOpenKeyEx(hkeyProgID, NULL, 0L, MAXIMUM_ALLOWED, &this->_hkeyProgID);
  232.      }
  233.  
  234.      // Get the path to the drop target folder
  235.      if (pidlFolder) {
  236.     SHGetPathFromIDList(pidlFolder, this->_szTargetFolder);
  237.      }
  238.  
  239.      return NOERROR;
  240. }
  241.  
  242. #pragma argsused
  243. STDMETHODIMP DropExt_QueryContextMenu(LPCONTEXTMENU pctm,
  244.                                                               HMENU hmenu,
  245.                                                               UINT indexMenu,
  246.                                                               UINT idCmdFirst,
  247.                                                               UINT idCmdLast,
  248.                              UINT uFlags)
  249. {
  250.      UINT idCmd = idCmdFirst;
  251.      InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, "Check H&DROP (dropext)");
  252.      InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, "Check H&NRES (dropext)");
  253.      return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)2));
  254. }
  255.  
  256. //
  257. // Converts an offset to a string to a string pointer.
  258. //
  259. LPCSTR _Offset2Ptr(LPSTR pszBase, UINT offset, UINT * pcb)
  260. {
  261.     LPSTR pszRet;
  262.     if (offset==0) {
  263.     pszRet = NULL;
  264.     *pcb = 0;
  265.     } else {
  266.     pszRet = pszBase + offset;
  267.     *pcb = lstrlen(pszRet) + 1;
  268.     }
  269.     return pszRet;
  270. }
  271.  
  272. //
  273. // This is a helper routine which extracts a specified NETRESOURCE from hnres.
  274. //
  275. UINT DropExt_GetNetResource(HGLOBAL hnres, UINT iItem, LPNETRESOURCE pnresOut, UINT cbMax)
  276. {
  277.     LPNRESARRAY panr = GlobalLock(hnres);
  278.     UINT iRet = 0;    // assume error
  279.     if (hnres)
  280.     {
  281.     if (iItem==(UINT)-1)
  282.     {
  283.         iRet = panr->cItems;
  284.     }
  285.     else if (iItem < panr->cItems)
  286.     {
  287.         UINT cbProvider, cbRemoteName;
  288.         LPCSTR pszProvider = _Offset2Ptr((LPSTR)panr, (UINT)panr->nr[iItem].lpProvider, &cbProvider);
  289.         LPCSTR pszRemoteName = _Offset2Ptr((LPSTR)panr, (UINT)panr->nr[iItem].lpRemoteName, &cbRemoteName);
  290.         iRet = sizeof(NETRESOURCE) + cbProvider + cbRemoteName;
  291.         if (iRet <= cbMax)
  292.         {
  293.         LPSTR psz = (LPSTR)(pnresOut+1);
  294.         *pnresOut = panr->nr[iItem];
  295.         if (pnresOut->lpProvider) {
  296.             pnresOut->lpProvider = psz;
  297.             lstrcpy(psz, pszProvider);
  298.             psz += cbProvider;
  299.         }
  300.         if (pnresOut->lpRemoteName) {
  301.             pnresOut->lpRemoteName = psz;
  302.             lstrcpy(psz, pszRemoteName);
  303.         }
  304.         }
  305.     }
  306.     GlobalUnlock(hnres);
  307.     }
  308.     return iRet;
  309. }
  310.  
  311. HRESULT DropExt_CheckForHDROP(PSAMPLEDROPEXT this, HWND hwnd)
  312. {
  313.     FORMATETC fmte = {
  314.             CF_HDROP,
  315.             (DVTARGETDEVICE FAR *)NULL,
  316.             DVASPECT_CONTENT,
  317.             -1,
  318.             TYMED_HGLOBAL };
  319.     STGMEDIUM medium;
  320.     HRESULT hres = this->_pdtobj->lpVtbl->GetData(this->_pdtobj, &fmte, &medium);
  321.  
  322.     if (SUCCEEDED(hres))
  323.     {
  324.  
  325.     // STGMEDIUM uses anonymous unions, which are not supported in C.
  326.     // The code below is conditionalized to show you how the usage differs
  327.     // between C and C++.
  328.     #if defined (__cplusplus)
  329.     HDROP hdrop = medium.hGlobal;
  330.     #else
  331.     HDROP hdrop = medium.u.hGlobal;
  332.     #endif
  333.  
  334.     UINT cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
  335.     char szFile[MAX_PATH];
  336.     char szBuf[MAX_PATH*2+64];
  337.  
  338.     DragQueryFile(hdrop, 0, szFile, sizeof(szFile));
  339.     wsprintf(szBuf,
  340.          "The drop target is %s.\n"
  341.          "%d files/directories in HDROP\n"
  342.          "The path to the first object is\n"
  343.              "\t%s.",
  344.          this->_szTargetFolder,
  345.          cFiles,
  346.          szFile);
  347.  
  348.     MessageBox(hwnd, szBuf, "DropExt", MB_OK);
  349.  
  350.     //
  351.     // HACK: We are supposed to call ReleaseStgMedium. This is a temporary
  352.     //  hack until OLE 2.01 for Windows 95 is released.
  353.     //
  354.     if (medium.pUnkForRelease)
  355.     {
  356.          medium.pUnkForRelease->lpVtbl->Release(medium.pUnkForRelease);
  357.     }
  358.     else
  359.     {
  360.  
  361.          // STGMEDIUM uses anonymous unions, which are not supported in C.
  362.          // The code below is conditionalized to show you how the usage differs
  363.          // between C and C++.
  364.          #if defined (__cplusplus)
  365.          GlobalFree(medium.hGlobal);
  366.          #else
  367.          GlobalFree(medium.u.hGlobal);
  368.          #endif
  369.     }
  370.      }
  371.     else
  372.      {
  373.     MessageBox(hwnd, "No file system object in the selection", "DropExt", MB_OK);
  374.     }
  375.  
  376.      return hres;
  377. }
  378.  
  379. HRESULT DropExt_CheckForHNRES(PSAMPLEDROPEXT this, HWND hwnd)
  380. {
  381.      FORMATETC fmte;
  382.      STGMEDIUM medium;
  383.      HRESULT hres;
  384.  
  385.      fmte.cfFormat =  (CLIPFORMAT) (g_cfNetResource ? g_cfNetResource
  386.         : (g_cfNetResource = RegisterClipboardFormat("Net Resource")));
  387.      fmte.ptd = (DVTARGETDEVICE FAR *)NULL;
  388.      fmte.dwAspect = DVASPECT_CONTENT;
  389.      fmte.lindex = -1;
  390.      fmte.tymed = TYMED_HGLOBAL;
  391.  
  392.      hres = this->_pdtobj->lpVtbl->GetData(this->_pdtobj, &fmte, &medium);
  393.  
  394.      if (SUCCEEDED(hres))
  395.      {
  396.  
  397.     // STGMEDIUM uses anonymous unions, which are not supported in C.
  398.     // The code below is conditionalized to show you how the usage differs
  399.     // between C and C++.
  400.     #if defined (__cplusplus)
  401.     HDROP hnres = medium.hGlobal;
  402.     #else
  403.     HDROP hnres = medium.u.hGlobal;
  404.     #endif
  405.  
  406.     LPNETRESOURCE pnr = (LPNETRESOURCE)LocalAlloc(LPTR, 1024);
  407.  
  408.     if (pnr)
  409.     {
  410.         char szBuf[512];
  411.         UINT cItems = DropExt_GetNetResource(hnres, (UINT)-1, NULL, 0);
  412.  
  413.         // Get the NETRESOURCE of the first item
  414.         DropExt_GetNetResource(hnres, 0, pnr, 1024);
  415.  
  416.         wsprintf(szBuf,
  417.              "%d network resource objects in HNRES\n"
  418.              "The attributes of the first object are\n"
  419.              "\tProvider      = %s\n"
  420.              "\tRemoteName    = %s\n"
  421.              "\tdwDisplayType = %x\n"
  422.              "\tdwType        = %x\n"
  423.              "\tdwUsage       = %x\n",
  424.               cItems,
  425.              pnr->lpProvider,
  426.              pnr->lpRemoteName ? pnr->lpRemoteName : "N/A",
  427.              pnr->dwDisplayType,
  428.              pnr->dwType,
  429.              pnr->dwUsage);
  430.  
  431.         MessageBox(hwnd, szBuf, "DropExt", MB_OK);
  432.  
  433.         LocalFree(pnr);
  434.     }
  435.     else
  436.     {
  437.         hres = ResultFromScode(E_OUTOFMEMORY);
  438.     }
  439.  
  440.     //
  441.     // HACK: We are supposed to call ReleaseStgMedium. This is a temporary
  442.     //  hack until OLE 2.01 for Windows 95 is released.
  443.     //
  444.     if (medium.pUnkForRelease)
  445.     {
  446.         medium.pUnkForRelease->lpVtbl->Release(medium.pUnkForRelease);
  447.     }
  448.     else
  449.     {
  450.          // STGMEDIUM uses anonymous unions, which are not supported in C.
  451.          // The code below is conditionalized to show you how the usage differs
  452.          // between C and C++.
  453.          #if defined (__cplusplus)
  454.          GlobalFree(medium.hGlobal);
  455.          #else
  456.          GlobalFree(medium.u.hGlobal);
  457.          #endif
  458.     }
  459.      }
  460.     else
  461.     {
  462.     MessageBox(hwnd, "No network objects in the selection", "DropExt", MB_OK);
  463.     }
  464.     return hres;
  465. }
  466.  
  467. STDMETHODIMP DropExt_InvokeCommand(LPCONTEXTMENU pctm,
  468.                    LPCMINVOKECOMMANDINFO lpici)
  469. {
  470.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  471.     HRESULT hres = ResultFromScode(E_INVALIDARG);    // assume error
  472.     //
  473.     // No need to support string based command.
  474.     //
  475.     if (!HIWORD(lpici->lpVerb))
  476.     {
  477.     UINT idCmd = LOWORD(lpici->lpVerb);
  478.  
  479.     switch(idCmd)
  480.     {
  481.     case 0:
  482.         hres = DropExt_CheckForHDROP(this, lpici->hwnd);
  483.         break;
  484.  
  485.     case 1:
  486.         hres = DropExt_CheckForHNRES(this, lpici->hwnd);
  487.         break;
  488.     }
  489.      }
  490.      return hres;
  491. }
  492.  
  493. #pragma argsused
  494. STDMETHODIMP DropExt_GetCommandString(
  495.                                                      LPCONTEXTMENU pctm,
  496.                                                      UINT        idCmd,
  497.                                                      UINT        wReserved,
  498.                                                      UINT FAR *  pwReserved,
  499.                                                      LPSTR       pszName,
  500.                                                      UINT        cchMax)
  501. {
  502.      return NOERROR;
  503. }
  504.  
  505. //---------------------------------------------------------------------------
  506. // CSampleDropExt::AddRef (IContextMenu override)
  507. //---------------------------------------------------------------------------
  508.  
  509. STDMETHODIMP_(UINT) DropExt_CTM_AddRef(LPCONTEXTMENU pctm)
  510. {
  511.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  512.     return ++this->_cRef;
  513. }
  514.  
  515.  
  516. //---------------------------------------------------------------------------
  517. // CSampleDropExt::AddRef (IShellExtInit override)
  518. //---------------------------------------------------------------------------
  519.  
  520. STDMETHODIMP_(UINT) DropExt_SXI_AddRef(LPSHELLEXTINIT psxi)
  521. {
  522.     PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  523.     return ++this->_cRef;
  524. }
  525.  
  526. //---------------------------------------------------------------------------
  527. // CSampleDropExt::Release (IContextMenu override)
  528. //---------------------------------------------------------------------------
  529.  
  530. STDMETHODIMP_(UINT) DropExt_CTM_Release(LPCONTEXTMENU pctm)
  531. {
  532.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  533.     if (--this->_cRef) {
  534.     return this->_cRef;
  535.     }
  536.  
  537.     if (this->_pdtobj) {
  538.     this->_pdtobj->lpVtbl->Release(this->_pdtobj);
  539.     }
  540.  
  541.     if (this->_hkeyProgID) {
  542.     RegCloseKey(this->_hkeyProgID);
  543.     }
  544.  
  545.     LocalFree((HLOCAL)this);
  546.     g_cRefThisDll--;
  547.  
  548.     return 0;
  549. }
  550.  
  551. //---------------------------------------------------------------------------
  552. // CSampleDropExt::Release (IShellExtInit thunk)
  553. //---------------------------------------------------------------------------
  554.  
  555. STDMETHODIMP_(UINT) DropExt_SXI_Release(LPSHELLEXTINIT psxi)
  556. {
  557.     PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  558.     return DropExt_CTM_Release(&this->_ctm);
  559. }
  560.  
  561. //---------------------------------------------------------------------------
  562. // CSampleDropExt::QueryInterface (IContextMenu override)
  563. //---------------------------------------------------------------------------
  564.  
  565. STDMETHODIMP DropExt_CTM_QueryInterface(LPCONTEXTMENU pctm, REFIID riid, LPVOID FAR* ppvOut)
  566. {
  567.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  568.     if (IsEqualIID(riid, &IID_IContextMenu) || IsEqualIID(riid, &IID_IUnknown))
  569.     {
  570.         (LPCONTEXTMENU)*ppvOut=pctm;
  571.         this->_cRef++;
  572.         return NOERROR;
  573.     }
  574.     if (IsEqualIID(riid, &IID_IShellExtInit))
  575.     {
  576.         (LPSHELLEXTINIT)*ppvOut=&this->_sxi;
  577.         this->_cRef++;
  578.         return NOERROR;
  579.     }
  580.     return ResultFromScode(E_NOINTERFACE);
  581. }
  582.  
  583. //---------------------------------------------------------------------------
  584. // CSampleDropExt::QueryInterface (IShellExtInit thunk)
  585. //---------------------------------------------------------------------------
  586.  
  587. STDMETHODIMP DropExt_SXI_QueryInterface(LPSHELLEXTINIT psxi, REFIID riid, LPVOID FAR* ppv)
  588. {
  589.     PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  590.     return DropExt_CTM_QueryInterface(&this->_ctm, riid, ppv);
  591. }
  592.  
  593.  
  594. //---------------------------------------------------------------------------
  595. // CSampleDropExt class : Vtables
  596. //---------------------------------------------------------------------------
  597.  
  598. #pragma data_seg(".text")
  599. #pragma warn -sus
  600. IContextMenuVtbl c_SampleDropExt_CTMVtbl = {
  601.      DropExt_CTM_QueryInterface,
  602.      DropExt_CTM_AddRef,
  603.     DropExt_CTM_Release,
  604.     DropExt_QueryContextMenu,
  605.     DropExt_InvokeCommand,
  606.     DropExt_GetCommandString,
  607. };
  608.  
  609. IShellExtInitVtbl c_SampleDropExt_SXIVtbl = {
  610.      DropExt_SXI_QueryInterface,
  611.      DropExt_SXI_AddRef,
  612.      DropExt_SXI_Release,
  613.      DropExt_Initialize
  614. };
  615. #pragma warn .sus
  616. #pragma data_seg()
  617.